home *** CD-ROM | disk | FTP | other *** search
/ Introduction to 3D Game …ogramming with DirectX 12 / Introduction-to-3D-Game-Programming-with-DirectX-12.ISO / Code.Textures / Chapter 9 Texturing / Crate / CrateApp.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2016-03-02  |  26.7 KB  |  754 lines

  1. //***************************************************************************************
  2. // CrateApp.cpp by Frank Luna (C) 2015 All Rights Reserved.
  3. //***************************************************************************************
  4.  
  5. #include "../../Common/d3dApp.h"
  6. #include "../../Common/MathHelper.h"
  7. #include "../../Common/UploadBuffer.h"
  8. #include "../../Common/GeometryGenerator.h"
  9. #include "FrameResource.h"
  10.  
  11. using Microsoft::WRL::ComPtr;
  12. using namespace DirectX;
  13. using namespace DirectX::PackedVector;
  14.  
  15. #pragma comment(lib, "d3dcompiler.lib")
  16. #pragma comment(lib, "D3D12.lib")
  17.  
  18. const int gNumFrameResources = 3;
  19.  
  20. // Lightweight structure stores parameters to draw a shape.  This will
  21. // vary from app-to-app.
  22. struct RenderItem
  23. {
  24.     RenderItem() = default;
  25.  
  26.     // World matrix of the shape that describes the object's local space
  27.     // relative to the world space, which defines the position, orientation,
  28.     // and scale of the object in the world.
  29.     XMFLOAT4X4 World = MathHelper::Identity4x4();
  30.  
  31.     XMFLOAT4X4 TexTransform = MathHelper::Identity4x4();
  32.  
  33.     // Dirty flag indicating the object data has changed and we need to update the constant buffer.
  34.     // Because we have an object cbuffer for each FrameResource, we have to apply the
  35.     // update to each FrameResource.  Thus, when we modify obect data we should set 
  36.     // NumFramesDirty = gNumFrameResources so that each frame resource gets the update.
  37.     int NumFramesDirty = gNumFrameResources;
  38.  
  39.     // Index into GPU constant buffer corresponding to the ObjectCB for this render item.
  40.     UINT ObjCBIndex = -1;
  41.  
  42.     Material* Mat = nullptr;
  43.     MeshGeometry* Geo = nullptr;
  44.  
  45.     // Primitive topology.
  46.     D3D12_PRIMITIVE_TOPOLOGY PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  47.  
  48.     // DrawIndexedInstanced parameters.
  49.     UINT IndexCount = 0;
  50.     UINT StartIndexLocation = 0;
  51.     int BaseVertexLocation = 0;
  52. };
  53.  
  54. class CrateApp : public D3DApp
  55. {
  56. public:
  57.     CrateApp(HINSTANCE hInstance);
  58.     CrateApp(const CrateApp& rhs) = delete;
  59.     CrateApp& operator=(const CrateApp& rhs) = delete;
  60.     ~CrateApp();
  61.  
  62.     virtual bool Initialize()override;
  63.  
  64. private:
  65.     virtual void OnResize()override;
  66.     virtual void Update(const GameTimer& gt)override;
  67.     virtual void Draw(const GameTimer& gt)override;
  68.  
  69.     virtual void OnMouseDown(WPARAM btnState, int x, int y)override;
  70.     virtual void OnMouseUp(WPARAM btnState, int x, int y)override;
  71.     virtual void OnMouseMove(WPARAM btnState, int x, int y)override;
  72.  
  73.     void OnKeyboardInput(const GameTimer& gt);
  74.     void UpdateCamera(const GameTimer& gt);
  75.     void AnimateMaterials(const GameTimer& gt);
  76.     void UpdateObjectCBs(const GameTimer& gt);
  77.     void UpdateMaterialCBs(const GameTimer& gt);
  78.     void UpdateMainPassCB(const GameTimer& gt);
  79.  
  80.     void LoadTextures();
  81.     void BuildRootSignature();
  82.     void BuildDescriptorHeaps();
  83.     void BuildShadersAndInputLayout();
  84.     void BuildShapeGeometry();
  85.     void BuildPSOs();
  86.     void BuildFrameResources();
  87.     void BuildMaterials();
  88.     void BuildRenderItems();
  89.     void DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems);
  90.  
  91.     std::array<const CD3DX12_STATIC_SAMPLER_DESC, 6> GetStaticSamplers();
  92.  
  93. private:
  94.  
  95.     std::vector<std::unique_ptr<FrameResource>> mFrameResources;
  96.     FrameResource* mCurrFrameResource = nullptr;
  97.     int mCurrFrameResourceIndex = 0;
  98.  
  99.     UINT mCbvSrvDescriptorSize = 0;
  100.  
  101.     ComPtr<ID3D12RootSignature> mRootSignature = nullptr;
  102.  
  103.     ComPtr<ID3D12DescriptorHeap> mSrvDescriptorHeap = nullptr;
  104.  
  105.     std::unordered_map<std::string, std::unique_ptr<MeshGeometry>> mGeometries;
  106.     std::unordered_map<std::string, std::unique_ptr<Material>> mMaterials;
  107.     std::unordered_map<std::string, std::unique_ptr<Texture>> mTextures;
  108.     std::unordered_map<std::string, ComPtr<ID3DBlob>> mShaders;
  109.  
  110.     std::vector<D3D12_INPUT_ELEMENT_DESC> mInputLayout;
  111.  
  112.     ComPtr<ID3D12PipelineState> mOpaquePSO = nullptr;
  113.  
  114.     // List of all the render items.
  115.     std::vector<std::unique_ptr<RenderItem>> mAllRitems;
  116.  
  117.     // Render items divided by PSO.
  118.     std::vector<RenderItem*> mOpaqueRitems;
  119.  
  120.     PassConstants mMainPassCB;
  121.  
  122.     XMFLOAT3 mEyePos = { 0.0f, 0.0f, 0.0f };
  123.     XMFLOAT4X4 mView = MathHelper::Identity4x4();
  124.     XMFLOAT4X4 mProj = MathHelper::Identity4x4();
  125.  
  126.     float mTheta = 1.3f*XM_PI;
  127.     float mPhi = 0.4f*XM_PI;
  128.     float mRadius = 2.5f;
  129.  
  130.     POINT mLastMousePos;
  131. };
  132.  
  133. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
  134.     PSTR cmdLine, int showCmd)
  135. {
  136.     // Enable run-time memory check for debug builds.
  137. #if defined(DEBUG) | defined(_DEBUG)
  138.     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
  139. #endif
  140.  
  141.     try
  142.     {
  143.         CrateApp theApp(hInstance);
  144.         if(!theApp.Initialize())
  145.             return 0;
  146.  
  147.         return theApp.Run();
  148.     }
  149.     catch(DxException& e)
  150.     {
  151.         MessageBox(nullptr, e.ToString().c_str(), L"HR Failed", MB_OK);
  152.         return 0;
  153.     }
  154. }
  155.  
  156. CrateApp::CrateApp(HINSTANCE hInstance)
  157.     : D3DApp(hInstance)
  158. {
  159. }
  160.  
  161. CrateApp::~CrateApp()
  162. {
  163.     if(md3dDevice != nullptr)
  164.         FlushCommandQueue();
  165. }
  166.  
  167. bool CrateApp::Initialize()
  168. {
  169.     if(!D3DApp::Initialize())
  170.         return false;
  171.  
  172.     // Reset the command list to prep for initialization commands.
  173.     ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));
  174.  
  175.     // Get the increment size of a descriptor in this heap type.  This is hardware specific, 
  176.     // so we have to query this information.
  177.     mCbvSrvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
  178.  
  179.  
  180.     LoadTextures();
  181.     BuildRootSignature();
  182.     BuildDescriptorHeaps();
  183.     BuildShadersAndInputLayout();
  184.     BuildShapeGeometry();
  185.     BuildMaterials();
  186.     BuildRenderItems();
  187.     BuildFrameResources();
  188.     BuildPSOs();
  189.  
  190.     // Execute the initialization commands.
  191.     ThrowIfFailed(mCommandList->Close());
  192.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  193.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  194.  
  195.     // Wait until initialization is complete.
  196.     FlushCommandQueue();
  197.  
  198.     return true;
  199. }
  200.  
  201. void CrateApp::OnResize()
  202. {
  203.     D3DApp::OnResize();
  204.  
  205.     // The window resized, so update the aspect ratio and recompute the projection matrix.
  206.     XMMATRIX P = XMMatrixPerspectiveFovLH(0.25f*MathHelper::Pi, AspectRatio(), 1.0f, 1000.0f);
  207.     XMStoreFloat4x4(&mProj, P);
  208. }
  209.  
  210. void CrateApp::Update(const GameTimer& gt)
  211. {
  212.     OnKeyboardInput(gt);
  213.     UpdateCamera(gt);
  214.  
  215.     // Cycle through the circular frame resource array.
  216.     mCurrFrameResourceIndex = (mCurrFrameResourceIndex + 1) % gNumFrameResources;
  217.     mCurrFrameResource = mFrameResources[mCurrFrameResourceIndex].get();
  218.  
  219.     // Has the GPU finished processing the commands of the current frame resource?
  220.     // If not, wait until the GPU has completed commands up to this fence point.
  221.     if(mCurrFrameResource->Fence != 0 && mFence->GetCompletedValue() < mCurrFrameResource->Fence)
  222.     {
  223.         HANDLE eventHandle = CreateEventEx(nullptr, false, false, EVENT_ALL_ACCESS);
  224.         ThrowIfFailed(mFence->SetEventOnCompletion(mCurrFrameResource->Fence, eventHandle));
  225.         WaitForSingleObject(eventHandle, INFINITE);
  226.         CloseHandle(eventHandle);
  227.     }
  228.  
  229.     AnimateMaterials(gt);
  230.     UpdateObjectCBs(gt);
  231.     UpdateMaterialCBs(gt);
  232.     UpdateMainPassCB(gt);
  233. }
  234.  
  235. void CrateApp::Draw(const GameTimer& gt)
  236. {
  237.     auto cmdListAlloc = mCurrFrameResource->CmdListAlloc;
  238.  
  239.     // Reuse the memory associated with command recording.
  240.     // We can only reset when the associated command lists have finished execution on the GPU.
  241.     ThrowIfFailed(cmdListAlloc->Reset());
  242.  
  243.     // A command list can be reset after it has been added to the command queue via ExecuteCommandList.
  244.     // Reusing the command list reuses memory.
  245.     ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mOpaquePSO.Get()));
  246.  
  247.     mCommandList->RSSetViewports(1, &mScreenViewport);
  248.     mCommandList->RSSetScissorRects(1, &mScissorRect);
  249.  
  250.     // Indicate a state transition on the resource usage.
  251.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  252.         D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
  253.  
  254.     // Clear the back buffer and depth buffer.
  255.     mCommandList->ClearRenderTargetView(CurrentBackBufferView(), Colors::LightSteelBlue, 0, nullptr);
  256.     mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
  257.  
  258.     // Specify the buffers we are going to render to.
  259.     mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());
  260.  
  261.     ID3D12DescriptorHeap* descriptorHeaps[] = { mSrvDescriptorHeap.Get() };
  262.     mCommandList->SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps);
  263.  
  264.     mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
  265.  
  266.     auto passCB = mCurrFrameResource->PassCB->Resource();
  267.     mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress());
  268.  
  269.     DrawRenderItems(mCommandList.Get(), mOpaqueRitems);
  270.  
  271.     // Indicate a state transition on the resource usage.
  272.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  273.         D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
  274.  
  275.     // Done recording commands.
  276.     ThrowIfFailed(mCommandList->Close());
  277.  
  278.     // Add the command list to the queue for execution.
  279.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  280.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  281.  
  282.     // Swap the back and front buffers
  283.     ThrowIfFailed(mSwapChain->Present(0, 0));
  284.     mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;
  285.  
  286.     // Advance the fence value to mark commands up to this fence point.
  287.     mCurrFrameResource->Fence = ++mCurrentFence;
  288.  
  289.     // Add an instruction to the command queue to set a new fence point. 
  290.     // Because we are on the GPU timeline, the new fence point won't be 
  291.     // set until the GPU finishes processing all the commands prior to this Signal().
  292.     mCommandQueue->Signal(mFence.Get(), mCurrentFence);
  293. }
  294.  
  295. void CrateApp::OnMouseDown(WPARAM btnState, int x, int y)
  296. {
  297.     mLastMousePos.x = x;
  298.     mLastMousePos.y = y;
  299.  
  300.     SetCapture(mhMainWnd);
  301. }
  302.  
  303. void CrateApp::OnMouseUp(WPARAM btnState, int x, int y)
  304. {
  305.     ReleaseCapture();
  306. }
  307.  
  308. void CrateApp::OnMouseMove(WPARAM btnState, int x, int y)
  309. {
  310.     if((btnState & MK_LBUTTON) != 0)
  311.     {
  312.         // Make each pixel correspond to a quarter of a degree.
  313.         float dx = XMConvertToRadians(0.25f*static_cast<float>(x - mLastMousePos.x));
  314.         float dy = XMConvertToRadians(0.25f*static_cast<float>(y - mLastMousePos.y));
  315.  
  316.         // Update angles based on input to orbit camera around box.
  317.         mTheta += dx;
  318.         mPhi += dy;
  319.  
  320.         // Restrict the angle mPhi.
  321.         mPhi = MathHelper::Clamp(mPhi, 0.1f, MathHelper::Pi - 0.1f);
  322.     }
  323.     else if((btnState & MK_RBUTTON) != 0)
  324.     {
  325.         // Make each pixel correspond to 0.2 unit in the scene.
  326.         float dx = 0.05f*static_cast<float>(x - mLastMousePos.x);
  327.         float dy = 0.05f*static_cast<float>(y - mLastMousePos.y);
  328.  
  329.         // Update the camera radius based on input.
  330.         mRadius += dx - dy;
  331.  
  332.         // Restrict the radius.
  333.         mRadius = MathHelper::Clamp(mRadius, 5.0f, 150.0f);
  334.     }
  335.  
  336.     mLastMousePos.x = x;
  337.     mLastMousePos.y = y;
  338. }
  339.  
  340. void CrateApp::OnKeyboardInput(const GameTimer& gt)
  341. {
  342. }
  343.  
  344. void CrateApp::UpdateCamera(const GameTimer& gt)
  345. {
  346.     // Convert Spherical to Cartesian coordinates.
  347.     mEyePos.x = mRadius*sinf(mPhi)*cosf(mTheta);
  348.     mEyePos.z = mRadius*sinf(mPhi)*sinf(mTheta);
  349.     mEyePos.y = mRadius*cosf(mPhi);
  350.  
  351.     // Build the view matrix.
  352.     XMVECTOR pos = XMVectorSet(mEyePos.x, mEyePos.y, mEyePos.z, 1.0f);
  353.     XMVECTOR target = XMVectorZero();
  354.     XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
  355.  
  356.     XMMATRIX view = XMMatrixLookAtLH(pos, target, up);
  357.     XMStoreFloat4x4(&mView, view);
  358. }
  359.  
  360. void CrateApp::AnimateMaterials(const GameTimer& gt)
  361. {
  362.     
  363. }
  364.  
  365. void CrateApp::UpdateObjectCBs(const GameTimer& gt)
  366. {
  367.     auto currObjectCB = mCurrFrameResource->ObjectCB.get();
  368.     for(auto& e : mAllRitems)
  369.     {
  370.         // Only update the cbuffer data if the constants have changed.  
  371.         // This needs to be tracked per frame resource.
  372.         if(e->NumFramesDirty > 0)
  373.         {
  374.             XMMATRIX world = XMLoadFloat4x4(&e->World);
  375.             XMMATRIX texTransform = XMLoadFloat4x4(&e->TexTransform);
  376.  
  377.             ObjectConstants objConstants;
  378.             XMStoreFloat4x4(&objConstants.World, XMMatrixTranspose(world));
  379.             XMStoreFloat4x4(&objConstants.TexTransform, XMMatrixTranspose(texTransform));
  380.  
  381.             currObjectCB->CopyData(e->ObjCBIndex, objConstants);
  382.  
  383.             // Next FrameResource need to be updated too.
  384.             e->NumFramesDirty--;
  385.         }
  386.     }
  387. }
  388.  
  389. void CrateApp::UpdateMaterialCBs(const GameTimer& gt)
  390. {
  391.     auto currMaterialCB = mCurrFrameResource->MaterialCB.get();
  392.     for(auto& e : mMaterials)
  393.     {
  394.         // Only update the cbuffer data if the constants have changed.  If the cbuffer
  395.         // data changes, it needs to be updated for each FrameResource.
  396.         Material* mat = e.second.get();
  397.         if(mat->NumFramesDirty > 0)
  398.         {
  399.             XMMATRIX matTransform = XMLoadFloat4x4(&mat->MatTransform);
  400.  
  401.             MaterialConstants matConstants;
  402.             matConstants.DiffuseAlbedo = mat->DiffuseAlbedo;
  403.             matConstants.FresnelR0 = mat->FresnelR0;
  404.             matConstants.Roughness = mat->Roughness;
  405.             XMStoreFloat4x4(&matConstants.MatTransform, XMMatrixTranspose(matTransform));
  406.  
  407.             currMaterialCB->CopyData(mat->MatCBIndex, matConstants);
  408.  
  409.             // Next FrameResource need to be updated too.
  410.             mat->NumFramesDirty--;
  411.         }
  412.     }
  413. }
  414.  
  415. void CrateApp::UpdateMainPassCB(const GameTimer& gt)
  416. {
  417.     XMMATRIX view = XMLoadFloat4x4(&mView);
  418.     XMMATRIX proj = XMLoadFloat4x4(&mProj);
  419.  
  420.     XMMATRIX viewProj = XMMatrixMultiply(view, proj);
  421.     XMMATRIX invView = XMMatrixInverse(&XMMatrixDeterminant(view), view);
  422.     XMMATRIX invProj = XMMatrixInverse(&XMMatrixDeterminant(proj), proj);
  423.     XMMATRIX invViewProj = XMMatrixInverse(&XMMatrixDeterminant(viewProj), viewProj);
  424.  
  425.     XMStoreFloat4x4(&mMainPassCB.View, XMMatrixTranspose(view));
  426.     XMStoreFloat4x4(&mMainPassCB.InvView, XMMatrixTranspose(invView));
  427.     XMStoreFloat4x4(&mMainPassCB.Proj, XMMatrixTranspose(proj));
  428.     XMStoreFloat4x4(&mMainPassCB.InvProj, XMMatrixTranspose(invProj));
  429.     XMStoreFloat4x4(&mMainPassCB.ViewProj, XMMatrixTranspose(viewProj));
  430.     XMStoreFloat4x4(&mMainPassCB.InvViewProj, XMMatrixTranspose(invViewProj));
  431.     mMainPassCB.EyePosW = mEyePos;
  432.     mMainPassCB.RenderTargetSize = XMFLOAT2((float)mClientWidth, (float)mClientHeight);
  433.     mMainPassCB.InvRenderTargetSize = XMFLOAT2(1.0f / mClientWidth, 1.0f / mClientHeight);
  434.     mMainPassCB.NearZ = 1.0f;
  435.     mMainPassCB.FarZ = 1000.0f;
  436.     mMainPassCB.TotalTime = gt.TotalTime();
  437.     mMainPassCB.DeltaTime = gt.DeltaTime();
  438.     mMainPassCB.AmbientLight = { 0.25f, 0.25f, 0.35f, 1.0f };
  439.     mMainPassCB.Lights[0].Direction = { 0.57735f, -0.57735f, 0.57735f };
  440.     mMainPassCB.Lights[0].Strength = { 0.6f, 0.6f, 0.6f };
  441.     mMainPassCB.Lights[1].Direction = { -0.57735f, -0.57735f, 0.57735f };
  442.     mMainPassCB.Lights[1].Strength = { 0.3f, 0.3f, 0.3f };
  443.     mMainPassCB.Lights[2].Direction = { 0.0f, -0.707f, -0.707f };
  444.     mMainPassCB.Lights[2].Strength = { 0.15f, 0.15f, 0.15f };
  445.  
  446.     auto currPassCB = mCurrFrameResource->PassCB.get();
  447.     currPassCB->CopyData(0, mMainPassCB);
  448. }
  449.  
  450. void CrateApp::LoadTextures()
  451. {
  452.     auto woodCrateTex = std::make_unique<Texture>();
  453.     woodCrateTex->Name = "woodCrateTex";
  454.     woodCrateTex->Filename = L"../../Textures/WoodCrate01.dds";
  455.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  456.         mCommandList.Get(), woodCrateTex->Filename.c_str(),
  457.         woodCrateTex->Resource, woodCrateTex->UploadHeap));
  458.  
  459.     mTextures[woodCrateTex->Name] = std::move(woodCrateTex);
  460. }
  461.  
  462. void CrateApp::BuildRootSignature()
  463. {
  464.     CD3DX12_DESCRIPTOR_RANGE texTable;
  465.     texTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);
  466.  
  467.     // Root parameter can be a table, root descriptor or root constants.
  468.     CD3DX12_ROOT_PARAMETER slotRootParameter[4];
  469.  
  470.     // Perfomance TIP: Order from most frequent to least frequent.
  471.     slotRootParameter[0].InitAsDescriptorTable(1, &texTable, D3D12_SHADER_VISIBILITY_PIXEL);
  472.     slotRootParameter[1].InitAsConstantBufferView(0);
  473.     slotRootParameter[2].InitAsConstantBufferView(1);
  474.     slotRootParameter[3].InitAsConstantBufferView(2);
  475.  
  476.     auto staticSamplers = GetStaticSamplers();
  477.  
  478.     // A root signature is an array of root parameters.
  479.     CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(4, slotRootParameter,
  480.         (UINT)staticSamplers.size(), staticSamplers.data(),
  481.         D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
  482.  
  483.     // create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
  484.     ComPtr<ID3DBlob> serializedRootSig = nullptr;
  485.     ComPtr<ID3DBlob> errorBlob = nullptr;
  486.     HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
  487.         serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
  488.  
  489.     if(errorBlob != nullptr)
  490.     {
  491.         ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
  492.     }
  493.     ThrowIfFailed(hr);
  494.  
  495.     ThrowIfFailed(md3dDevice->CreateRootSignature(
  496.         0,
  497.         serializedRootSig->GetBufferPointer(),
  498.         serializedRootSig->GetBufferSize(),
  499.         IID_PPV_ARGS(mRootSignature.GetAddressOf())));
  500. }
  501.  
  502. void CrateApp::BuildDescriptorHeaps()
  503. {
  504.     //
  505.     // Create the SRV heap.
  506.     //
  507.     D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
  508.     srvHeapDesc.NumDescriptors = 1;
  509.     srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
  510.     srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
  511.     ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&mSrvDescriptorHeap)));
  512.  
  513.     //
  514.     // Fill out the heap with actual descriptors.
  515.     //
  516.     CD3DX12_CPU_DESCRIPTOR_HANDLE hDescriptor(mSrvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
  517.  
  518.     auto woodCrateTex = mTextures["woodCrateTex"]->Resource;
  519.  
  520.     D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
  521.     srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
  522.     srvDesc.Format = woodCrateTex->GetDesc().Format;
  523.     srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
  524.     srvDesc.Texture2D.MostDetailedMip = 0;
  525.     srvDesc.Texture2D.MipLevels = woodCrateTex->GetDesc().MipLevels;
  526.     srvDesc.Texture2D.ResourceMinLODClamp = 0.0f;
  527.  
  528.     md3dDevice->CreateShaderResourceView(woodCrateTex.Get(), &srvDesc, hDescriptor);
  529. }
  530.  
  531. void CrateApp::BuildShadersAndInputLayout()
  532. {
  533.     mShaders["standardVS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", nullptr, "VS", "vs_5_0");
  534.     mShaders["opaquePS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", nullptr, "PS", "ps_5_0");
  535.     
  536.     mInputLayout =
  537.     {
  538.         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  539.         { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  540.         { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  541.     };
  542. }
  543.  
  544. void CrateApp::BuildShapeGeometry()
  545. {
  546.     GeometryGenerator geoGen;
  547.     GeometryGenerator::MeshData box = geoGen.CreateBox(1.0f, 1.0f, 1.0f, 3);
  548.  
  549.     SubmeshGeometry boxSubmesh;
  550.     boxSubmesh.IndexCount = (UINT)box.Indices32.size();
  551.     boxSubmesh.StartIndexLocation = 0;
  552.     boxSubmesh.BaseVertexLocation = 0;
  553.  
  554.  
  555.     std::vector<Vertex> vertices(box.Vertices.size());
  556.  
  557.     for(size_t i = 0; i < box.Vertices.size(); ++i)
  558.     {
  559.         vertices[i].Pos = box.Vertices[i].Position;
  560.         vertices[i].Normal = box.Vertices[i].Normal;
  561.         vertices[i].TexC = box.Vertices[i].TexC;
  562.     }
  563.  
  564.     std::vector<std::uint16_t> indices = box.GetIndices16();
  565.  
  566.     const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
  567.     const UINT ibByteSize = (UINT)indices.size()  * sizeof(std::uint16_t);
  568.  
  569.     auto geo = std::make_unique<MeshGeometry>();
  570.     geo->Name = "boxGeo";
  571.  
  572.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
  573.     CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  574.  
  575.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  576.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  577.  
  578.     geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  579.         mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
  580.  
  581.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  582.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  583.  
  584.     geo->VertexByteStride = sizeof(Vertex);
  585.     geo->VertexBufferByteSize = vbByteSize;
  586.     geo->IndexFormat = DXGI_FORMAT_R16_UINT;
  587.     geo->IndexBufferByteSize = ibByteSize;
  588.  
  589.     geo->DrawArgs["box"] = boxSubmesh;
  590.  
  591.     mGeometries[geo->Name] = std::move(geo);
  592. }
  593.  
  594. void CrateApp::BuildPSOs()
  595. {
  596.     D3D12_GRAPHICS_PIPELINE_STATE_DESC opaquePsoDesc;
  597.  
  598.     //
  599.     // PSO for opaque objects.
  600.     //
  601.     ZeroMemory(&opaquePsoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
  602.     opaquePsoDesc.InputLayout = { mInputLayout.data(), (UINT)mInputLayout.size() };
  603.     opaquePsoDesc.pRootSignature = mRootSignature.Get();
  604.     opaquePsoDesc.VS = 
  605.     { 
  606.         reinterpret_cast<BYTE*>(mShaders["standardVS"]->GetBufferPointer()), 
  607.         mShaders["standardVS"]->GetBufferSize()
  608.     };
  609.     opaquePsoDesc.PS = 
  610.     { 
  611.         reinterpret_cast<BYTE*>(mShaders["opaquePS"]->GetBufferPointer()),
  612.         mShaders["opaquePS"]->GetBufferSize()
  613.     };
  614.     opaquePsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
  615.     opaquePsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
  616.     opaquePsoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
  617.     opaquePsoDesc.SampleMask = UINT_MAX;
  618.     opaquePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
  619.     opaquePsoDesc.NumRenderTargets = 1;
  620.     opaquePsoDesc.RTVFormats[0] = mBackBufferFormat;
  621.     opaquePsoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
  622.     opaquePsoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
  623.     opaquePsoDesc.DSVFormat = mDepthStencilFormat;
  624.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&opaquePsoDesc, IID_PPV_ARGS(&mOpaquePSO)));
  625. }
  626.  
  627. void CrateApp::BuildFrameResources()
  628. {
  629.     for(int i = 0; i < gNumFrameResources; ++i)
  630.     {
  631.         mFrameResources.push_back(std::make_unique<FrameResource>(md3dDevice.Get(),
  632.             1, (UINT)mAllRitems.size(), (UINT)mMaterials.size()));
  633.     }
  634. }
  635.  
  636. void CrateApp::BuildMaterials()
  637. {
  638.     auto woodCrate = std::make_unique<Material>();
  639.     woodCrate->Name = "woodCrate";
  640.     woodCrate->MatCBIndex = 0;
  641.     woodCrate->DiffuseSrvHeapIndex = 0;
  642.     woodCrate->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  643.     woodCrate->FresnelR0 = XMFLOAT3(0.05f, 0.05f, 0.05f);
  644.     woodCrate->Roughness = 0.2f;
  645.  
  646.     mMaterials["woodCrate"] = std::move(woodCrate);
  647. }
  648.  
  649. void CrateApp::BuildRenderItems()
  650. {
  651.     auto boxRitem = std::make_unique<RenderItem>();
  652.     boxRitem->ObjCBIndex = 0;
  653.     boxRitem->Mat = mMaterials["woodCrate"].get();
  654.     boxRitem->Geo = mGeometries["boxGeo"].get();
  655.     boxRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  656.     boxRitem->IndexCount = boxRitem->Geo->DrawArgs["box"].IndexCount;
  657.     boxRitem->StartIndexLocation = boxRitem->Geo->DrawArgs["box"].StartIndexLocation;
  658.     boxRitem->BaseVertexLocation = boxRitem->Geo->DrawArgs["box"].BaseVertexLocation;
  659.     mAllRitems.push_back(std::move(boxRitem));
  660.  
  661.     // All the render items are opaque.
  662.     for(auto& e : mAllRitems)
  663.         mOpaqueRitems.push_back(e.get());
  664. }
  665.  
  666. void CrateApp::DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems)
  667. {
  668.     UINT objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
  669.     UINT matCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(MaterialConstants));
  670.  
  671.     auto objectCB = mCurrFrameResource->ObjectCB->Resource();
  672.     auto matCB = mCurrFrameResource->MaterialCB->Resource();
  673.  
  674.     // For each render item...
  675.     for(size_t i = 0; i < ritems.size(); ++i)
  676.     {
  677.         auto ri = ritems[i];
  678.  
  679.         cmdList->IASetVertexBuffers(0, 1, &ri->Geo->VertexBufferView());
  680.         cmdList->IASetIndexBuffer(&ri->Geo->IndexBufferView());
  681.         cmdList->IASetPrimitiveTopology(ri->PrimitiveType);
  682.  
  683.         CD3DX12_GPU_DESCRIPTOR_HANDLE tex(mSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
  684.         tex.Offset(ri->Mat->DiffuseSrvHeapIndex, mCbvSrvDescriptorSize);
  685.  
  686.         D3D12_GPU_VIRTUAL_ADDRESS objCBAddress = objectCB->GetGPUVirtualAddress() + ri->ObjCBIndex*objCBByteSize;
  687.         D3D12_GPU_VIRTUAL_ADDRESS matCBAddress = matCB->GetGPUVirtualAddress() + ri->Mat->MatCBIndex*matCBByteSize;
  688.  
  689.         cmdList->SetGraphicsRootDescriptorTable(0, tex);
  690.         cmdList->SetGraphicsRootConstantBufferView(1, objCBAddress);
  691.         cmdList->SetGraphicsRootConstantBufferView(3, matCBAddress);
  692.  
  693.         cmdList->DrawIndexedInstanced(ri->IndexCount, 1, ri->StartIndexLocation, ri->BaseVertexLocation, 0);
  694.     }
  695. }
  696.  
  697. std::array<const CD3DX12_STATIC_SAMPLER_DESC, 6> CrateApp::GetStaticSamplers()
  698. {
  699.     // Applications usually only need a handful of samplers.  So just define them all up front
  700.     // and keep them available as part of the root signature.  
  701.  
  702.     const CD3DX12_STATIC_SAMPLER_DESC pointWrap(
  703.         0, // shaderRegister
  704.         D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
  705.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  706.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  707.         D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
  708.  
  709.     const CD3DX12_STATIC_SAMPLER_DESC pointClamp(
  710.         1, // shaderRegister
  711.         D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
  712.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  713.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  714.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
  715.  
  716.     const CD3DX12_STATIC_SAMPLER_DESC linearWrap(
  717.         2, // shaderRegister
  718.         D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
  719.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  720.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  721.         D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
  722.  
  723.     const CD3DX12_STATIC_SAMPLER_DESC linearClamp(
  724.         3, // shaderRegister
  725.         D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
  726.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  727.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  728.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
  729.  
  730.     const CD3DX12_STATIC_SAMPLER_DESC anisotropicWrap(
  731.         4, // shaderRegister
  732.         D3D12_FILTER_ANISOTROPIC, // filter
  733.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  734.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  735.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressW
  736.         0.0f,                             // mipLODBias
  737.         8);                               // maxAnisotropy
  738.  
  739.     const CD3DX12_STATIC_SAMPLER_DESC anisotropicClamp(
  740.         5, // shaderRegister
  741.         D3D12_FILTER_ANISOTROPIC, // filter
  742.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  743.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  744.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressW
  745.         0.0f,                              // mipLODBias
  746.         8);                                // maxAnisotropy
  747.  
  748.     return { 
  749.         pointWrap, pointClamp,
  750.         linearWrap, linearClamp, 
  751.         anisotropicWrap, anisotropicClamp };
  752. }
  753.  
  754.